package hero

import (
	"bytes"
	"io/ioutil"
	"os"
	"path/filepath"
	"reflect"
	"regexp"
	"strings"
	"testing"
)

var replacer = regexp.MustCompile(`\s`)

func TestWriteToFile(t *testing.T) {
	path := "/tmp/hero.test"
	content := "hello, hero"

	buffer := bytes.NewBufferString(content)
	writeToFile(path, buffer)

	defer os.Remove(path)

	if _, err := os.Stat(path); err != nil {
		t.Fatal(err)
	}

	if c, err := ioutil.ReadFile(path); err != nil {
		t.Fatal(err)
	} else if string(c) != content {
		t.Fatalf("want: %s got: %s", content, c)
	}
}

func TestGenAbsPath(t *testing.T) {
	dir, err := filepath.Abs("./")
	if err != nil {
		t.Fatal(err)
	}

	parts := strings.Split(dir, string(filepath.Separator))
	parent := strings.Join(parts[:len(parts)-1], string(filepath.Separator))

	root := os.Args[0]
	for root != filepath.Dir(root) {
		root = filepath.Dir(root)
	}

	cases := []struct {
		in  string
		out string
	}{
		{in: "/", out: root},
		{in: ".", out: dir},
		{in: "../", out: parent},
	}

	for _, c := range cases {
		got := genAbsPath(c.in)
		if got != c.out {
			t.Errorf("want: %s got: %s", c.out, got)
		}
	}
}

func TestGenerate(t *testing.T) {
	Generate(rootDir, rootDir, "template")

	cases := []struct {
		file string
		code string
	}{
		{file: "index.html.go", code: `
// Code generated by hero.
// source: ` + filepath.Join(rootDir, "index.html") + `
// DO NOT EDIT!
package template
`},
		{file: "item.html.go", code: `
// Code generated by hero.
// source: ` + filepath.Join(rootDir, "item.html") + `
// DO NOT EDIT!
package template
`},
		{file: "list.html.go", code: `
// Code generated by hero.
// source: ` + filepath.Join(rootDir, "list.html") + `
// DO NOT EDIT!
package template

import (
	"bytes"

	"github.com/shiyanhui/hero"
)

func Add(a, b int) int {
	return a + b
}
func UserList(userList []string, buffer *bytes.Buffer) {
	buffer.WriteString(` + "`" + `
<!DOCTYPE html>
<html>
  <head>
  </head>
  <body>
    ` + "`" + `)
	for _, user := range userList {
		buffer.WriteString(` + "`" + `
<div>
    <a href="/user/` + "`" + `)
		hero.EscapeHTML(user, buffer)
		buffer.WriteString(` + "`" + `">
        ` + "`" + `)
		buffer.WriteString(user)
		buffer.WriteString(` + "`" + `
    </a>
</div>
` + "`" + `)

	}

	buffer.WriteString(` + "`" + `
  </body>
</html>
` + "`" + `)

}
		`},
		{file: "listwriter.html.go", code: `
// Code generated by hero.
// source: ` + filepath.Join(rootDir, "listwriter.html") + `
// DO NOT EDIT!
package template

import (
	"io"

	"github.com/shiyanhui/hero"
)

func UserListToWriter(userList []string, w io.Writer) {
	_buffer := hero.GetBuffer()
	defer hero.PutBuffer(_buffer)
	_buffer.WriteString(` + "`" + `
<!DOCTYPE html>
<html>
  <head>
  </head>
  <body>
    ` + "`" + `)
	for _, user := range userList {
		_buffer.WriteString(` + "`" + `
<div>
    <a href="/user/` + "`" + `)
		hero.EscapeHTML(user, _buffer)
		_buffer.WriteString(` + "`" + `">
        ` + "`" + `)
		_buffer.WriteString(user)
		_buffer.WriteString(` + "`" + `
    </a>
</div>
` + "`" + `)

	}

	_buffer.WriteString(` + "`" + `
  </body>
</html>
` + "`" + `)
	w.Write(_buffer.Bytes())
}
		`},
		{file: "listwriterresult.html.go", code: `
// Code generated by hero.
// source: ` + filepath.Join(rootDir, "listwriterresult.html") + `
// DO NOT EDIT!
package template

import (
	"io"

	"github.com/shiyanhui/hero"
)

func UserListToWriterWithResult(userList []string, w io.Writer) (n int, err error) {
	_buffer := hero.GetBuffer()
	defer hero.PutBuffer(_buffer)
	_buffer.WriteString(` + "`" + `
<!DOCTYPE html>
<html>
  <head>
  </head>
  <body>
    ` + "`" + `)
	for _, user := range userList {
		_buffer.WriteString(` + "`" + `
<div>
    <a href="/user/` + "`" + `)
		hero.EscapeHTML(user, _buffer)
		_buffer.WriteString(` + "`" + `">
        ` + "`" + `)
		_buffer.WriteString(user)
		_buffer.WriteString(` + "`" + `
    </a>
</div>
` + "`" + `)

	}

	_buffer.WriteString(` + "`" + `
  </body>
</html>
` + "`" + `)
	return w.Write(_buffer.Bytes())
}
		`},
	}

	for _, c := range cases {
		content, err := ioutil.ReadFile(filepath.Join(rootDir, c.file))
		if err != nil {
			t.Error(err)
			continue
		}
		got := replacer.ReplaceAll(content, nil)
		want := []byte(replacer.ReplaceAllString(c.code, ""))
		if !reflect.DeepEqual(got, want) {
			t.Errorf("\nfile: %s\n\nwant:\n%s\n\ngot:\n%s\n", c.file, want, got)
		}
	}
}

func TestGen(t *testing.T) {
	root := parseFile(rootDir, "list.html")
	buffer := new(bytes.Buffer)
	bufName := "_buffer"

	gen(root, buffer, bufName)

	if buffer.String() == replacer.ReplaceAllString(
		`for _, user := range userList {}`, "") {
		t.Fail()
	}
}
